<template>
  <div class="code-preview">
    <!-- 预览工具栏 -->
    <div class="preview-toolbar">
      <div class="toolbar-left">
        <el-radio-group v-model="previewMode" size="small">
          <el-radio-button label="split">
            <el-icon><Grid /></el-icon>
            分屏
          </el-radio-button>
          <el-radio-button label="code">
            <el-icon><Document /></el-icon>
            代码
          </el-radio-button>
          <el-radio-button label="preview">
            <el-icon><View /></el-icon>
            预览
          </el-radio-button>
        </el-radio-group>
        
        <el-divider direction="vertical" />
        
        <el-select v-model="codeLanguage" size="small" style="width: 120px">
          <el-option label="Vue 3" value="vue" />
          <el-option label="React" value="react" />
          <el-option label="HTML" value="html" />
          <el-option label="JSON" value="json" />
        </el-select>
      </div>
      
      <div class="toolbar-right">
        <el-button-group size="small">
          <el-button @click="formatCode">
            <el-icon><MagicStick /></el-icon>
            格式化
          </el-button>
          <el-button @click="copyCode">
            <el-icon><DocumentCopy /></el-icon>
            复制
          </el-button>
          <el-button @click="downloadCode">
            <el-icon><Download /></el-icon>
            下载
          </el-button>
        </el-button-group>
        
        <el-button size="small" @click="toggleFullscreen">
          <el-icon><FullScreen /></el-icon>
        </el-button>
      </div>
    </div>

    <!-- 预览内容区 -->
    <div class="preview-content" :class="`mode-${previewMode}`">
      <!-- 代码编辑区 -->
      <div v-show="previewMode !== 'preview'" class="code-panel">
        <div class="panel-header">
          <span>代码</span>
          <div class="header-actions">
            <el-tag size="small">{{ codeLanguage.toUpperCase() }}</el-tag>
            <el-tag size="small" type="info">{{ codeLines }} 行</el-tag>
          </div>
        </div>
        
        <div class="code-editor">
          <div class="line-numbers">
            <div v-for="n in codeLines" :key="n" class="line-number">
              {{ n }}
            </div>
          </div>
          
          <textarea
            v-model="code"
            class="code-textarea"
            :placeholder="`输入${codeLanguage}代码...`"
            spellcheck="false"
            @input="handleCodeChange"
          ></textarea>
        </div>
      </div>

      <!-- 预览区 -->
      <div v-show="previewMode !== 'code'" class="preview-panel">
        <div class="panel-header">
          <span>实时预览</span>
          <div class="header-actions">
            <el-radio-group v-model="previewDevice" size="small">
              <el-radio-button label="desktop">
                <el-icon><Monitor /></el-icon>
              </el-radio-button>
              <el-radio-button label="tablet">
                <el-icon><Iphone /></el-icon>
              </el-radio-button>
              <el-radio-button label="mobile">
                <el-icon><Cellphone /></el-icon>
              </el-radio-button>
            </el-radio-group>
            
            <el-button text @click="refreshPreview">
              <el-icon><Refresh /></el-icon>
            </el-button>
          </div>
        </div>
        
        <div class="preview-container" :class="`device-${previewDevice}`">
          <div v-if="previewError" class="preview-error">
            <el-icon class="error-icon"><WarningFilled /></el-icon>
            <h3>预览出错</h3>
            <p>{{ previewError }}</p>
            <el-button size="small" @click="refreshPreview">重试</el-button>
          </div>
          
          <iframe
            v-else
            ref="previewFrame"
            class="preview-iframe"
            sandbox="allow-scripts"
            :srcdoc="previewHtml"
          ></iframe>
        </div>
      </div>
    </div>

    <!-- 控制台输出 -->
    <transition name="slide-up">
      <div v-show="showConsole" class="console-panel">
        <div class="console-header">
          <span>控制台</span>
          <div class="console-actions">
            <el-button text size="small" @click="clearConsole">
              <el-icon><Delete /></el-icon>
              清空
            </el-button>
            <el-button text size="small" @click="showConsole = false">
              <el-icon><Close /></el-icon>
            </el-button>
          </div>
        </div>
        
        <div class="console-content">
          <div
            v-for="(log, index) in consoleLogs"
            :key="index"
            class="console-log"
            :class="`log-${log.type}`"
          >
            <span class="log-time">{{ formatTime(log.time) }}</span>
            <el-icon v-if="log.type === 'error'" class="log-icon"><CircleClose /></el-icon>
            <el-icon v-else-if="log.type === 'warn'" class="log-icon"><Warning /></el-icon>
            <el-icon v-else class="log-icon"><InfoFilled /></el-icon>
            <span class="log-message">{{ log.message }}</span>
          </div>
          
          <el-empty v-if="consoleLogs.length === 0" description="暂无日志" :image-size="60" />
        </div>
      </div>
    </transition>

    <!-- 底部状态栏 -->
    <div class="status-bar">
      <div class="status-left">
        <span class="status-item">
          <el-icon><Document /></el-icon>
          {{ fileName }}
        </span>
        <span v-if="lastSaved" class="status-item">
          <el-icon><Clock /></el-icon>
          最后保存: {{ formatTime(lastSaved) }}
        </span>
      </div>
      
      <div class="status-right">
        <el-button text size="small" @click="showConsole = !showConsole">
          <el-icon><Promotion /></el-icon>
          控制台 {{ consoleLogs.length > 0 ? `(${consoleLogs.length})` : '' }}
        </el-button>
        
        <span class="status-item">
          <el-icon><Timer /></el-icon>
          编译: {{ compileTime }}ms
        </span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import {
  Grid,
  Document,
  View,
  MagicStick,
  DocumentCopy,
  Download,
  FullScreen,
  Monitor,
  Iphone,
  Cellphone,
  Refresh,
  WarningFilled,
  Delete,
  Close,
  CircleClose,
  Warning,
  InfoFilled,
  Clock,
  Promotion,
  Timer
} from '@element-plus/icons-vue'

const props = defineProps({
  initialCode: {
    type: String,
    default: ''
  },
  language: {
    type: String,
    default: 'vue'
  },
  autoPreview: {
    type: Boolean,
    default: true
  }
})

const emit = defineEmits(['update:code', 'save'])

const previewMode = ref('split')
const codeLanguage = ref(props.language)
const previewDevice = ref('desktop')
const code = ref(props.initialCode)
const previewHtml = ref('')
const previewError = ref('')
const showConsole = ref(false)
const consoleLogs = ref([])
const compileTime = ref(0)
const lastSaved = ref(null)
const fileName = ref('untitled.vue')
const previewFrame = ref(null)

// 计算代码行数
const codeLines = computed(() => {
  return code.value.split('\n').length
})

// 处理代码变化
const handleCodeChange = () => {
  emit('update:code', code.value)
  
  if (props.autoPreview) {
    debouncePreview()
  }
}

// 防抖预览
let previewTimer = null
const debouncePreview = () => {
  clearTimeout(previewTimer)
  previewTimer = setTimeout(() => {
    updatePreview()
  }, 500)
}

// 更新预览
const updatePreview = () => {
  const startTime = performance.now()
  previewError.value = ''
  
  try {
    // 根据语言类型生成预览HTML
    let html = ''
    
    switch (codeLanguage.value) {
      case 'vue':
        html = generateVuePreview(code.value)
        break
      case 'react':
        html = generateReactPreview(code.value)
        break
      case 'html':
        html = code.value
        break
      case 'json':
        html = generateJsonPreview(code.value)
        break
      default:
        html = `<pre>${code.value}</pre>`
    }
    
    previewHtml.value = wrapPreviewHtml(html)
    compileTime.value = Math.round(performance.now() - startTime)
    
    addConsoleLog('info', '预览更新成功')
  } catch (error) {
    previewError.value = error.message
    addConsoleLog('error', `预览失败: ${error.message}`)
  }
}

// 生成Vue预览
const generateVuePreview = (vueCode) => {
  // 简化实现，实际需要编译器
  return `
    <div id="app">
      <div style="padding: 20px;">
        ${vueCode}
      </div>
    </div>
  `
}

// 生成React预览
const generateReactPreview = (reactCode) => {
  return `<div id="root">${reactCode}</div>`
}

// 生成JSON预览
const generateJsonPreview = (jsonCode) => {
  try {
    const data = JSON.parse(jsonCode)
    return `<pre style="padding: 20px;">${JSON.stringify(data, null, 2)}</pre>`
  } catch (e) {
    throw new Error('JSON格式错误')
  }
}

// 包装预览HTML
const wrapPreviewHtml = (content) => {
  return `
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link href="https://unpkg.com/element-plus/dist/index.css" rel="stylesheet">
      <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
      <script src="https://unpkg.com/element-plus"></script>
      <style>
        body {
          margin: 0;
          padding: 0;
          font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
        }
        * {
          box-sizing: border-box;
        }
      </style>
    </head>
    <body>
      ${content}
      <script>
        // 捕获控制台输出
        const originalConsole = {
          log: console.log,
          error: console.error,
          warn: console.warn
        };
        
        ['log', 'error', 'warn'].forEach(method => {
          console[method] = function(...args) {
            window.parent.postMessage({
              type: 'console',
              method: method,
              args: args
            }, '*');
            originalConsole[method].apply(console, args);
          };
        });
        
        // 错误捕获
        window.onerror = function(msg, url, line, col, error) {
          window.parent.postMessage({
            type: 'error',
            message: msg,
            line: line,
            col: col
          }, '*');
        };
      </script>
    </body>
    </html>
  `
}

// 格式化代码
const formatCode = () => {
  try {
    if (codeLanguage.value === 'json') {
      const data = JSON.parse(code.value)
      code.value = JSON.stringify(data, null, 2)
    } else {
      // 简单的格式化
      code.value = code.value
        .split('\n')
        .map(line => line.trim())
        .join('\n')
    }
    ElMessage.success('代码已格式化')
  } catch (error) {
    ElMessage.error('格式化失败: ' + error.message)
  }
}

// 复制代码
const copyCode = async () => {
  try {
    await navigator.clipboard.writeText(code.value)
    ElMessage.success('代码已复制到剪贴板')
  } catch (error) {
    ElMessage.error('复制失败')
  }
}

// 下载代码
const downloadCode = () => {
  const blob = new Blob([code.value], { type: 'text/plain' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = fileName.value
  a.click()
  URL.revokeObjectURL(url)
  ElMessage.success('代码已下载')
}

// 刷新预览
const refreshPreview = () => {
  updatePreview()
  ElMessage.success('预览已刷新')
}

// 全屏切换
const toggleFullscreen = () => {
  const elem = document.querySelector('.code-preview')
  if (!document.fullscreenElement) {
    elem.requestFullscreen()
  } else {
    document.exitFullscreen()
  }
}

// 添加控制台日志
const addConsoleLog = (type, message) => {
  consoleLogs.value.push({
    type,
    message,
    time: new Date().getTime()
  })
  
  // 最多保留100条
  if (consoleLogs.value.length > 100) {
    consoleLogs.value.shift()
  }
}

// 清空控制台
const clearConsole = () => {
  consoleLogs.value = []
}

// 格式化时间
const formatTime = (timestamp) => {
  const date = new Date(timestamp)
  return date.toLocaleTimeString('zh-CN')
}

// 监听iframe消息
const handleMessage = (event) => {
  if (event.data.type === 'console') {
    addConsoleLog(event.data.method, event.data.args.join(' '))
  } else if (event.data.type === 'error') {
    addConsoleLog('error', event.data.message)
  }
}

// 保存代码
const saveCode = () => {
  lastSaved.value = new Date().getTime()
  emit('save', code.value)
  ElMessage.success('代码已保存')
}

// 监听键盘快捷键
const handleKeyboard = (e) => {
  if (e.ctrlKey && e.key === 's') {
    e.preventDefault()
    saveCode()
  }
}

onMounted(() => {
  window.addEventListener('message', handleMessage)
  window.addEventListener('keydown', handleKeyboard)
  
  if (props.autoPreview) {
    updatePreview()
  }
})
</script>

<style scoped>
.code-preview {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: #fff;
  border-radius: 8px;
  overflow: hidden;
}

/* 工具栏 */
.preview-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid #e5e7eb;
  background: #f9fafb;
}

.toolbar-left,
.toolbar-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* 内容区 */
.preview-content {
  flex: 1;
  display: flex;
  overflow: hidden;
}

.preview-content.mode-split {
  .code-panel,
  .preview-panel {
    width: 50%;
  }
}

.preview-content.mode-code {
  .code-panel {
    width: 100%;
  }
}

.preview-content.mode-preview {
  .preview-panel {
    width: 100%;
  }
}

/* 面板 */
.code-panel,
.preview-panel {
  display: flex;
  flex-direction: column;
  border-right: 1px solid #e5e7eb;
}

.preview-panel {
  border-right: none;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background: #f9fafb;
  border-bottom: 1px solid #e5e7eb;
  font-weight: 500;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 代码编辑器 */
.code-editor {
  flex: 1;
  display: flex;
  overflow: hidden;
  background: #1e1e1e;
}

.line-numbers {
  padding: 16px 8px;
  background: #252526;
  color: #858585;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 14px;
  line-height: 1.6;
  user-select: none;
  text-align: right;
  min-width: 50px;
}

.line-number {
  height: 22.4px;
}

.code-textarea {
  flex: 1;
  padding: 16px;
  border: none;
  outline: none;
  background: #1e1e1e;
  color: #d4d4d4;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 14px;
  line-height: 1.6;
  resize: none;
}

/* 预览容器 */
.preview-container {
  flex: 1;
  position: relative;
  overflow: auto;
  background: #f5f5f5;
  transition: all 0.3s;
}

.preview-container.device-desktop {
  padding: 0;
}

.preview-container.device-tablet {
  padding: 20px;
}

.preview-container.device-tablet .preview-iframe {
  max-width: 768px;
  margin: 0 auto;
  border: 1px solid #ddd;
  border-radius: 8px;
}

.preview-container.device-mobile {
  padding: 20px;
}

.preview-container.device-mobile .preview-iframe {
  max-width: 375px;
  margin: 0 auto;
  border: 1px solid #ddd;
  border-radius: 8px;
}

.preview-iframe {
  width: 100%;
  height: 100%;
  border: none;
  background: white;
}

.preview-error {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 40px;
  text-align: center;
}

.error-icon {
  font-size: 48px;
  color: #f56c6c;
  margin-bottom: 16px;
}

.preview-error h3 {
  margin: 0 0 8px 0;
  color: #303133;
}

.preview-error p {
  margin: 0 0 20px 0;
  color: #909399;
}

/* 控制台 */
.console-panel {
  height: 200px;
  border-top: 1px solid #e5e7eb;
  display: flex;
  flex-direction: column;
  background: #fff;
}

.console-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 16px;
  background: #f9fafb;
  border-bottom: 1px solid #e5e7eb;
  font-size: 13px;
  font-weight: 500;
}

.console-actions {
  display: flex;
  gap: 8px;
}

.console-content {
  flex: 1;
  overflow-y: auto;
  padding: 8px;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 12px;
}

.console-log {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 4px 8px;
  border-bottom: 1px solid #f0f0f0;
}

.console-log.log-error {
  background: #fef0f0;
  color: #f56c6c;
}

.console-log.log-warn {
  background: #fdf6ec;
  color: #e6a23c;
}

.log-time {
  color: #909399;
  font-size: 11px;
}

.log-icon {
  flex-shrink: 0;
  margin-top: 2px;
}

.log-message {
  flex: 1;
  word-break: break-all;
}

/* 状态栏 */
.status-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 6px 16px;
  background: #f9fafb;
  border-top: 1px solid #e5e7eb;
  font-size: 12px;
  color: #606266;
}

.status-left,
.status-right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.status-item {
  display: flex;
  align-items: center;
  gap: 4px;
}

/* 动画 */
.slide-up-enter-active,
.slide-up-leave-active {
  transition: all 0.3s;
}

.slide-up-enter-from,
.slide-up-leave-to {
  transform: translateY(100%);
  opacity: 0;
}

/* 滚动条 */
.console-content::-webkit-scrollbar,
.preview-container::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.console-content::-webkit-scrollbar-thumb,
.preview-container::-webkit-scrollbar-thumb {
  background: #dcdfe6;
  border-radius: 4px;
}

.console-content::-webkit-scrollbar-thumb:hover,
.preview-container::-webkit-scrollbar-thumb:hover {
  background: #c0c4cc;
}
</style>


